﻿using StackExchange.Redis;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;

namespace Redis.Library
{
    /// <summary>
    /// Redis具体操作类
    /// </summary>
    public class RedisExtension
    {
        /// <summary>
        /// 倒序排例
        /// </summary>
        private const string DefaultOrder = "desc";

        private readonly int busyRetry = 5;

        private readonly int busyRetryWaitMS = 200;

        private readonly int dbIndex = -1;

        private readonly string sectionName;

        private readonly string exceptionHashId;

        /// <summary>
        /// Redis操作类构造
        /// </summary>
        /// <param name="sectionName"></param>
        /// <param name="dbIndex"></param>
        /// <param name="busyRetry"></param>
        /// <param name="busyRetryWaitMS"></param>
        public RedisExtension(string sectionName, int dbIndex = -1, int busyRetry = 5, int busyRetryWaitMS = 200)
        {
            this.sectionName = sectionName;
            this.dbIndex = dbIndex;
            this.busyRetry = busyRetry;
            this.busyRetryWaitMS = busyRetryWaitMS;

            if ((busyRetry < 0) || (busyRetry > 50))
                throw new Exception("重试次数有误，请输入0-50之间整数");

            if ((busyRetryWaitMS < 100) || (busyRetryWaitMS > 3000))
                throw new Exception("失败重试等待时长有误，请输入100-3000之间整数");
        }

        /// <summary>
        /// Redis操作类构造
        /// </summary>
        /// <param name="sectionName"></param>
        /// <param name="dbIndex"></param>
        /// <param name="busyRetry"></param>
        /// <param name="busyRetryWaitMS"></param>
        public RedisExtension(string sectionName, int dbIndex = -1,string exceptionHashId= "exception", int busyRetry = 5, int busyRetryWaitMS = 200)
        {
            this.sectionName = sectionName;
            this.dbIndex = dbIndex;
            this.busyRetry = busyRetry;
            this.busyRetryWaitMS = busyRetryWaitMS;
            this.exceptionHashId = exceptionHashId;

            if ((busyRetry < 0) || (busyRetry > 50))
                throw new Exception("重试次数有误，请输入0-50之间整数");

            if ((busyRetryWaitMS < 100) || (busyRetryWaitMS > 3000))
                throw new Exception("失败重试等待时长有误，请输入100-3000之间整数");
        }

        /// <summary>
        /// 获取服务器信息
        /// </summary>
        /// <returns></returns>
        public string GetServerInfo()
        {
            using (var cnn = new RedisConnection(sectionName, dbIndex))
            {
                return cnn.GetServerInfo();
            }
        }

        /// <summary>
        /// 获取全部keys(如果没有选着片，返回未提重的所有key)
        /// </summary>
        ///<param name="dbIndex">数据库片</param>
        /// <param name="patten"></param>
        /// <returns></returns>
        public List<string> GetKeys(int dbIndex = -1, string patten = "*")
        {
            return DoWithRetry(() =>
            {
                List<string> keys = new List<string>();
                if (dbIndex == -1)
                {
                    for (int i = 0; i < 16; i++)
                    {
                        using (var cnn = new RedisConnection(sectionName, i))
                        {
                            var result = cnn.GetDatabase().ScriptEvaluate(LuaScript.Prepare("return  redis.call('KEYS', '*')"), CommandFlags.PreferSlave);

                            if (!result.IsNull)
                            {
                                var list = (RedisResult[])result;
                                foreach (var item in list)
                                {
                                    var key = (RedisKey)item;
                                    keys.Add(key.ToString());
                                }
                            }
                        }
                    }
                }
                else
                {
                    using (var cnn = new RedisConnection(sectionName, dbIndex))
                    {
                        var result = cnn.GetDatabase().ScriptEvaluate(LuaScript.Prepare("return  redis.call('KEYS', '*')"), CommandFlags.PreferSlave);

                        if (!result.IsNull)
                        {
                            var list = (RedisResult[])result;
                            foreach (var item in list)
                            {
                                var key = (RedisKey)item;
                                keys.Add(key.ToString());
                            }
                        }
                    }
                }
                return keys;
            });
        }

        #region String Keys操作

        /// <summary>
        /// 是否存在key
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public bool StringKeyExists(string key)
        {
            return DoWithRetry(() =>
            {
                using (var cnn = new RedisConnection(sectionName, dbIndex))
                {
                    return cnn.GetDatabase().KeyExists(key);
                }
            });
        }

        /// <summary>
        /// 给key设置超时时间
        /// </summary>
        /// <param name="key"></param>
        /// <param name="timeout">超时时间（秒）</param>
        /// <returns></returns>
        public bool StringKeyExpire(string key, int timeout = 0)
        {
            return DoWithRetry(() =>
            {
                if (timeout > 0)
                    using (var cnn = new RedisConnection(sectionName, dbIndex))
                    {
                        return cnn.GetDatabase().KeyExpire(key, DateTime.Now.AddSeconds(timeout));
                    }
                return false;
            });
        }

        #region  添加

        /// <summary>
        /// 保存该key对应的字符串
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <param name="timeout">单位秒</param>
        /// <returns></returns>
        public bool StringSet(string key, string value, int timeout = 0)
        {
            return DoWithRetry(() =>
            {
                var bResult = false;
                if (timeout > 0)
                    using (var cnn = new RedisConnection(sectionName, dbIndex))
                    {
                        bResult = cnn.GetDatabase().StringSet(key, value, new TimeSpan(0, 0, timeout));
                    }
                else
                    using (var cnn = new RedisConnection(sectionName, dbIndex))
                    {
                        bResult = cnn.GetDatabase().StringSet(key, value);
                    }
                return bResult;
            });
        }

        /// <summary>
        /// 保存将实体转换成json的值
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <param name="t"></param>
        /// <param name="timeout"></param>
        /// <returns></returns>
        public bool StringSet<T>(string key, T t, int timeout = 0) where T : class, new()
        {
            return DoWithRetry(() =>
            {
                using (var cnn = new RedisConnection(sectionName, dbIndex))
                {
                    return StringSet(key, t.ToJson(), timeout);
                }
            });
        }

        /// <summary>
        /// 仅在该key不存在的时候保存
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <param name="timeout"></param>
        /// <returns></returns>
        public bool StringSetIfNotExists(string key, string value)
        {
            return DoWithRetry(() =>
            {
                using (var cnn = new RedisConnection(sectionName, dbIndex))
                {
                    return cnn.GetDatabase().StringSet(key, value, when: When.NotExists);
                }
            });
        }

        /// <summary>
        /// 批量插入
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <param name="t"></param>
        /// <param name="timeout"></param>
        /// <returns></returns>
        public bool StringSets<T>(List<string> key, List<T> t, int timeout = 0) where T : class, new()
        {
            return DoWithRetry(() =>
            {
                using (var cnn = new RedisConnection(sectionName, dbIndex))
                {
                    var batch = cnn.GetDatabase().CreateBatch();
                    if (timeout > 0)
                        for (int i = 0; i < t.Count; i++)
                        {
                            batch.StringSetAsync(key[i], t[i].ToJson(), new TimeSpan(0, 0, timeout));
                        }
                    else
                        for (int i = 0; i < t.Count; i++)
                        {
                            batch.StringSetAsync(key[i], t[i].ToJson());
                        }
                    batch.Execute();
                    return true;
                }
            });
        }

        #endregion

        #region  获取
        /// <summary>
        ///  根据key获取value
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public string StringGet(string key)
        {
            return DoWithRetry(() =>
            {
                using (var cnn = new RedisConnection(sectionName, dbIndex))
                {
                    return cnn.GetDatabase().StringGet(key);
                }
            });
        }

        /// <summary>
        /// 根据key获取对应的实体
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <returns></returns>
        public T StringGet<T>(string key) where T : class, new()
        {
            try
            {
                var str = StringGet(key);
                if (!string.IsNullOrWhiteSpace(str))
                {
                    return str.JsonToObject<T>();
                }
                return default(T);
            }
            catch (Exception ex)
            {
                throw new Exception("根据key获取对应的实体出错", ex);
            }
        }

        /// <summary>
        ///  获取keys对应的实体列表集合
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="keys"></param>
        /// <returns></returns>
        public List<T> StringGetValues<T>(List<string> keys) where T : class, new()
        {
            try
            {
                var list = new List<T>();
                if ((keys != null) && (keys.Count > 0))
                    foreach (var key in keys)
                    {
                        var item = StringGet<T>(key);
                        if (item != null)
                            list.Add(item);
                    }
                return list;
            }
            catch (Exception ex)
            {
                throw new Exception($"获取keys对应的实体列表集合出错,{ex.Message}", ex);
            }
        }

        /// <summary>
        /// 获取keys对应的字符串列表集合
        /// </summary>
        /// <param name="keys"></param>
        /// <returns></returns>
        public List<string> StringGetValues(List<string> keys)
        {
            try
            {
                var list = new List<string>();
                if ((keys != null) && (keys.Count > 0))
                    foreach (var key in keys)
                    {
                        var item = StringGet(key);
                        if (item != null)
                            list.Add(item);
                    }
                return list;
            }
            catch (Exception ex)
            {
                throw new Exception($"获取keys对应的字符串列表集合出错,{ex.Message}", ex);
            }
        }

        #endregion

        #region 删除

        /// <summary>
        /// 删除key对应的信息
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public bool StringKeyDelete(string key)
        {
            return DoWithRetry(() =>
            {
                using (var cnn = new RedisConnection(sectionName, dbIndex))
                {
                    return cnn.GetDatabase().KeyDelete(key);
                }
            });
        }

        /// <summary>
        ///  批量删除key对应的信息
        /// </summary>
        /// <param name="keys"></param>
        public void StringKeysDelete(List<string> keys)
        {
            try
            {
                using (var cnn = new RedisConnection(sectionName, dbIndex))
                {
                    var batch = cnn.GetDatabase().CreateBatch();
                    for (var i = 0; i < keys.Count; i++)
                        batch.KeyDeleteAsync(keys[i]);
                    batch.Execute();
                    //return true;
                }
            }
            catch (Exception ex)
            {
                throw new Exception($"批量删除key对应的信息发生错误,{ex.Message}", ex);
            }
        }


        #endregion

        #region  更新

        /// <summary>
        /// 重命名key
        /// </summary>
        /// <param name="oldKey"></param>
        /// <param name="newKey"></param>
        /// <returns></returns>
        public bool StringKeyRename(string oldKey, string newKey)
        {
            return DoWithRetry(() =>
            {
                using (var cnn = new RedisConnection(sectionName, dbIndex))
                {
                    return cnn.GetDatabase().KeyRename(oldKey, newKey);
                }
            });
        }

        /// <summary>
        /// 根据key获取原value的同时set该Key对应的新的value
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public string StringGetSet(string key, string value)
        {
            return DoWithRetry(() =>
            {
                using (var cnn = new RedisConnection(sectionName, dbIndex))
                {
                    return cnn.GetDatabase().StringGetSet(key, value);
                }
            });
        }

        /// <summary>
        /// 向对应key追加value
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public long StringAppend(string key, string value)
        {
            return DoWithRetry(() =>
            {
                using (var cnn = new RedisConnection(sectionName, dbIndex))
                {
                    return cnn.GetDatabase().StringAppend(key, value, CommandFlags.None);
                }
            });
        }

        #endregion

        #endregion

        #region Hashes操作

        /// <summary>
        /// 检查hash是否存在
        /// </summary>
        /// <param name="hashId"></param>
        /// <param name="key"></param>
        /// <returns></returns>
        public bool HashExists(string hashId, string key)
        {
            return DoWithRetry(() =>
            {
                using (var cnn = new RedisConnection(sectionName, dbIndex))
                {
                    return cnn.GetDatabase().HashExists(hashId, key);
                }
            });
        }

        #region 添加

        /// <summary>
        /// 将单个实体保存到hash表中(只能用于单条添加)
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="hashId"></param>
        /// <param name="key"></param>
        /// <param name="t"></param>
        /// <returns></returns>
        public bool HashSet<T>(string hashId, string key, T t) where T : class, new()
        {
            return DoWithRetry(() =>
            {
                using (var cnn = new RedisConnection(sectionName, dbIndex))
                {
                    return cnn.GetDatabase().HashSet(hashId, key, t.ToJson());
                }
            });
        }

        /// <summary>
        /// 将字符串保存到hash表中(只能用于单条添加)
        /// </summary>
        /// <param name="hashId"></param>
        /// <param name="key"></param>
        /// <param name="val"></param>
        /// <returns></returns>
        public bool HashSet(string hashId, string key, string val)
        {
            return DoWithRetry(() =>
            {
                using (var cnn = new RedisConnection(sectionName, dbIndex))
                {
                    return cnn.GetDatabase().HashSet(hashId, key, val);
                }
            });
        }

        /// <summary>
        /// 在一个hash中设置一个key - value，仅仅当不存在的时候才设置
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="hashId"></param>
        /// <param name="key"></param>
        /// <param name="t"></param>
        /// <returns></returns>
        public bool HashSetIfNotExists(string hashId, string key, string value)
        {
            return DoWithRetry(() =>
            {
                using (var cnn = new RedisConnection(sectionName, dbIndex))
                {
                    return cnn.GetDatabase().HashSet(hashId, key, value, When.NotExists);
                }
            });
        }

        /// <summary>
        /// hash批量插入
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="hashId"></param>
        /// <param name="keys"></param>
        /// <param name="t"></param>
        /// <returns></returns>
        public bool HashSets<T>(string hashId, List<string> keys, List<T> t)
        {
            return DoWithRetry(() =>
            {
                using (var cnn = new RedisConnection(sectionName, dbIndex))
                {
                    var batch = cnn.GetDatabase().CreateBatch();
                    for (int i = 0; i < t.Count; i++)
                    {
                        batch.HashSetAsync(hashId, keys[i], t[i].ToJson());
                    }
                    batch.Execute();
                    return true;
                }
            });
        }

        #endregion

        #region 查询

        /// <summary>
        /// 获取根据hashId和key获取单条实体信息(多10毫秒)
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="hashId"></param>
        /// <param name="key"></param>
        /// <returns></returns>
        public T HashGet<T>(string hashId, string key) where T : class, new()
        {
            return DoWithRetry(() =>
            {
                using (var cnn = new RedisConnection(sectionName, dbIndex))
                {
                    string str = cnn.GetDatabase().HashGet(hashId, key);
                    if (!string.IsNullOrWhiteSpace(str))
                        return str.JsonToObject<T>();
                    return default(T);
                }
            });
        }

        /// <summary>
        /// 获取根据hashId和key获取单条字符串信息
        /// </summary>
        /// <param name="hashId"></param>
        /// <param name="key"></param>
        /// <returns></returns>
        public string HashGet(string hashId, string key)
        {
            return DoWithRetry(() =>
            {
                using (var cnn = new RedisConnection(sectionName, dbIndex))
                {
                    return cnn.GetDatabase().HashGet(hashId, key).ToString();
                }
            });
        }

        /// <summary>
        /// 获取该hashId下hash表中数据条数
        /// </summary>
        /// <param name="hashId"></param>
        /// <returns></returns>
        public long HashCount(string hashId)
        {
            return DoWithRetry(() =>
            {
                using (var cnn = new RedisConnection(sectionName, dbIndex))
                {
                    return cnn.GetDatabase().HashLength(hashId);
                }
            });
        }

        /// <summary>
        ///获取某个hashid下面全部hash字符串
        /// </summary>
        /// <param name="hashId"></param>
        /// <returns></returns>
        public List<string> HashGetAll(string hashId)
        {
            return DoWithRetry(() =>
            {
                using (var cnn = new RedisConnection(sectionName, dbIndex))
                {
                    var result = new List<string>();
                    var list = cnn.GetDatabase().HashValues(hashId).ToList();

                    if ((list != null) && (list.Count > 0))
                        list.ForEach(x =>
                        {
                            if (x.HasValue)
                                result.Add(x.ToString());
                        });
                    return result;
                }
            });
        }

        /// <summary>
        /// 获取某个hashid下面全部hash实体
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="hashId"></param>
        /// <returns></returns>
        public List<T> HashGetAll<T>(string hashId) where T : class, new()
        {
            return DoWithRetry(() =>
            {
                using (var cnn = new RedisConnection(sectionName, dbIndex))
                {
                    var result = new List<T>();
                    var list = cnn.GetDatabase().HashValues(hashId).ToList();
                    if (list.Count > 0)
                        list.ForEach(x =>
                        {
                            if (x.HasValue)
                            {
                                var str = x.ToString();
                                if (!string.IsNullOrWhiteSpace(str))
                                {
                                    var t = str.JsonToObject<T>();
                                    if (t != null)
                                        result.Add(t);
                                }
                            }
                        });
                    return result;
                }
            });
        }

        /// <summary>
        ///  获取全部的hashkey,hashvalue字典
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="hashId"></param>
        /// <returns></returns>
        public Dictionary<string, T> HashGetAllDic<T>(string hashId) where T : class, new()
        {
            return DoWithRetry(() =>
            {
                using (var cnn = new RedisConnection(sectionName, dbIndex))
                {
                    var result = new Dictionary<string, T>();
                    var list = cnn.GetDatabase().HashGetAll(hashId).ToList();

                    if (list.Count > 0)
                        list.ForEach(x =>
                        {
                            var str = x.Value;
                            if (!string.IsNullOrWhiteSpace(str))
                            {
                                var value = str.ToString().JsonToObject<T>();// JsonHelper.NToData<T>(str);
                                result.Add(x.Name, value);
                            }
                        });
                    return result;
                }
            });
        }

        /// <summary>
        /// 获取全部的hashkey,hashvalue字典
        /// </summary>
        /// <param name="hashId"></param>
        /// <returns></returns>
        public Dictionary<string, string> HashGetAllDic(string hashId)
        {
            return DoWithRetry(() =>
            {
                using (var cnn = new RedisConnection(sectionName, dbIndex))
                {
                    var result = new Dictionary<string, string>();
                    var list = cnn.GetDatabase().HashGetAll(hashId).ToList();

                    if (list.Count > 0)
                        list.ForEach(x =>
                        {
                            result.Add(x.Name, x.Value);
                        });
                    return result;
                }
            });
        }

        /// <summary>
        ///分页某个hashid下面hash
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="hashId"></param>
        /// <param name="pageIndex"></param>
        /// <param name="pageSize"></param>
        /// <returns></returns>
        public List<T> HashGetPageList<T>(string hashId, int pageIndex, int pageSize) where T : class, new()
        {
            return DoWithRetry(() =>
            {
                using (var cnn = new RedisConnection(sectionName, dbIndex))
                {
                    var result = new List<T>();

                    pageIndex = pageIndex > 0 ? pageIndex : 1;
                    pageSize = pageSize > 0 ? pageSize : 20;

                    var list = cnn.GetDatabase().HashValues(hashId)
                                                .Skip((pageIndex - 1) * pageSize)
                                                .Take(pageSize)
                                                .ToList();

                    if ((list != null) && (list.Count > 0))
                        list.ForEach(value =>
                        {
                            if (!string.IsNullOrEmpty(value) && value.HasValue)
                            {
                                var obj = value.ToString().JsonToObject<T>(); ;// JsonHelper.NToData<T>(value.ToString());
                                if (obj != null)
                                    result.Add(obj);
                            }
                        });
                    return result;
                }
            });
        }


        /// <summary>
        ///  获取某个hashid下面全部keys
        /// </summary>
        /// <param name="hashId"></param>
        /// <returns></returns>
        public List<string> HashGetAllKeys(string hashId)
        {
            return DoWithRetry(() =>
            {
                using (var cnn = new RedisConnection(sectionName, dbIndex))
                {
                    var result = new List<string>();
                    var list = cnn.GetDatabase().HashKeys(hashId).ToList();
                    if (list.Count > 0)
                        list.ForEach(x =>
                        {
                            result.Add(x.ToString());
                        });
                    return result;
                }
            });
        }

        /// <summary>
        /// 从指定hashid,keys中获取指定hash实体集合
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="hashId"></param>
        /// <param name="keys"></param>
        /// <returns></returns>
        public List<T> HashGetValuesFromKeys<T>(string hashId, List<string> keys) where T : class, new()
        {
            return DoWithRetry(() =>
            {
                using (var cnn = new RedisConnection(sectionName, dbIndex))
                {
                    var list = new List<T>();
                    if ((keys != null) && (keys.Count > 0))
                    {
                        var rv = new RedisValue[keys.Count];
                        for (var i = 0; i < keys.Count; i++)
                            rv[i] = keys[i];
                        var vlts = cnn.GetDatabase().HashGet(hashId, rv);
                        foreach (var val in vlts)
                            if (!string.IsNullOrEmpty(val))
                            {
                                var obj = val.ToString().JsonToObject<T>(); //JsonHelper.NToData<T>(val);
                                if (obj != null)
                                    list.Add(obj);
                            }
                    }
                    return list;
                }
            });
        }

        /// <summary>
        /// 从指定hashid,keys中获取指定hash字符串集合
        /// </summary>
        /// <param name="hashId"></param>
        /// <param name="keys"></param>
        /// <returns></returns>
        public List<string> HashGetValuesFromKeys(string hashId, List<string> keys)
        {
            return DoWithRetry(() =>
            {
                using (var cnn = new RedisConnection(sectionName, dbIndex))
                {
                    var list = new List<string>();
                    if ((keys != null) && (keys.Count > 0))
                    {
                        var rv = new RedisValue[keys.Count];
                        for (var i = 0; i < keys.Count; i++)
                            rv[i] = keys[i];
                        var vlts = cnn.GetDatabase().HashGet(hashId, rv);
                        foreach (var val in vlts)
                            if (!string.IsNullOrEmpty(val) && val.HasValue)
                                list.Add(val);
                    }
                    return list;
                }
            });
        }

        #endregion

        #region 删除

        /// <summary>
        ///移除hash表中对应hashId，key记录
        /// </summary>
        /// <param name="hashId"></param>
        /// <param name="key"></param>
        /// <returns></returns>
        public bool HashDelete(string hashId, string key)
        {
            return DoWithRetry(() =>
            {
                using (var cnn = new RedisConnection(sectionName, dbIndex))
                {
                    return cnn.GetDatabase().HashDelete(hashId, key);
                }
            });
        }
        /// <summary>
        /// 批量移除
        /// </summary>
        /// <param name="hashId"></param>
        /// <param name="keys"></param>
        /// <returns></returns>
        public void HashDeletes(string hashId, List<string> keys)
        {
            DoWithRetry(() =>
            {
                using (var cnn = new RedisConnection(sectionName, dbIndex))
                {
                    for (var i = 0; i < keys.Count; i++)
                        cnn.GetDatabase().HashDelete(hashId, keys[i]);
                }
            });
        }
        #endregion

        #region 更新

        /// <summary>
        /// 根据hashId,Key,更新该行信息
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="hashId"></param>
        /// <param name="key"></param>
        /// <param name="func"></param>
        /// <returns></returns>
        public bool HashUpdate<T>(string hashId, string key, Func<T, T> func)
        {
            return DoWithRetry(() =>
            {
                using (var cnn = new RedisConnection(sectionName, dbIndex))
                {
                    var db = cnn.GetDatabase();

                    var query = db.HashGetAsync(hashId, key).Result;

                    db.HashSetAsync(hashId, key, func(query.ToString().JsonToObject<T>()).ToJson());

                    return true;
                }
            });
        }

        /// <summary>
        /// Hash递减操作
        /// </summary>
        /// <param name="hashId"></param>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public bool HashDecrement(string hashId, string key, long value = 1)
        {
            return DoWithRetry(() =>
            {
                using (var cnn = new RedisConnection(sectionName, dbIndex))
                {
                    var db = cnn.GetDatabase();

                    return db.HashDecrement(hashId, key, value)>0;
                }
            });
        }

        /// <summary>
        /// Hash异步递减操作
        /// </summary>
        /// <param name="hashId"></param>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public bool HashDecrementAsync(string hashId, string key, long value = 1)
        {
            return DoWithRetry(() =>
            {
                using (var cnn = new RedisConnection(sectionName, dbIndex))
                {
                    var db = cnn.GetDatabase();

                    db.HashDecrementAsync(hashId, key, value);

                    return true;
                }
            });
        }

        /// <summary>
        /// Hash递增操作
        /// </summary>
        /// <param name="hashId"></param>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public bool HashIncrement(string hashId, string key, long value = 1)
        {
            return DoWithRetry(() =>
            {
                using (var cnn = new RedisConnection(sectionName, dbIndex))
                {
                    var db = cnn.GetDatabase();

                    return db.HashIncrement(hashId, key, value) > 0;
                }
            });
        }

        /// <summary>
        /// Hash异步递增操作
        /// </summary>
        /// <param name="hashId"></param>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public bool HashIncrementAsync(string hashId, string key, long value = 1)
        {
            return DoWithRetry(() =>
            {
                using (var cnn = new RedisConnection(sectionName, dbIndex))
                {
                    var db = cnn.GetDatabase();

                    db.HashIncrementAsync(hashId, key, value);

                    return true;
                }
            });
        }

        #endregion

        #endregion

        #region Set操作

        #region 添加

        /// <summary>
        /// 添加一个set
        /// </summary>
        /// <param name="setId"></param>
        /// <param name="val"></param>
        /// <returns></returns>
        public bool SetAdd(string setId, string val)
        {
            return DoWithRetry(() =>
            {
                using (var cnn = new RedisConnection(sectionName, dbIndex))
                {
                    return cnn.GetDatabase().SetAdd(setId, val);
                }
            });
        }

        #endregion

        #region 查询

        /// <summary>
        /// 是否存在于set中
        /// </summary>
        /// <param name="setId"></param>
        /// <param name="val"></param>
        /// <returns></returns>
        public bool SetContains(string setId, string val)
        {
            return DoWithRetry(() =>
            {
                using (var cnn = new RedisConnection(sectionName, dbIndex))
                {
                    return cnn.GetDatabase().SetContains(setId, val);
                }
            });
        }

        /// <summary>
        /// 返回指定set长度
        /// </summary>
        /// <param name="setId"></param>
        /// <returns></returns>
        public long SetLength(string setId)
        {
            return DoWithRetry(() =>
            {
                using (var cnn = new RedisConnection(sectionName, dbIndex))
                {
                    return cnn.GetDatabase().SetLength(setId);
                }
            });
        }


        /// <summary>
        /// 获取某个key下面全部的value
        /// </summary>
        /// <param name="setId"></param>
        /// <returns></returns>
        public List<string> SetGetAllList(string setId)
        {
            return DoWithRetry(() =>
            {
                using (var cnn = new RedisConnection(sectionName, dbIndex))
                {
                    var values = cnn.GetDatabase().SetMembers(setId);
                    var list = new List<string>();
                    if ((values != null) && (values.Count() > 0))
                        foreach (var sitem in values)
                            list.Add(sitem.ToString());
                    return list;
                }
            });
        }

        #endregion

        #region 删除操作

        /// <summary>
        /// 移除set
        /// </summary>
        /// <param name="setId"></param>
        /// <param name="val"></param>
        /// <returns></returns>
        public bool SetRemove(string setId, string val)
        {
            return DoWithRetry(() =>
            {
                using (var cnn = new RedisConnection(sectionName, dbIndex))
                {
                    return cnn.GetDatabase().SetRemove(setId, val);
                }
            });
        }

        /// <summary>
        /// 批量删除set
        /// </summary>
        /// <param name="setId"></param>
        /// <param name="vals"></param>
        public void SetRemoves(string setId, List<string> vals)
        {
            DoWithRetry(() =>
            {
                using (var cnn = new RedisConnection(sectionName, dbIndex))
                {
                    for (var i = 0; i < vals.Count; i++)
                        cnn.GetDatabase().SetRemove(setId, vals[i]);
                }
            });
        }
        #endregion

        #endregion

        #region Sorted Sets 操作


        /// <summary>
        /// 检查SortedSet
        /// </summary>
        /// <param name="setId"></param>
        /// <param name="item"></param>
        /// <returns></returns>
        public bool SortedSetItemExists(string setId, string item)
        {
            try
            {
                var value = SortedSetGetScore(setId, item);
                if (value != null)
                    return true;
                return false;
            }
            catch (Exception ex)
            {
                throw new Exception($"检查SortedSet失败,{ex.Message}", ex);
            }
        }


        #region 添加

        /// <summary>
        /// 添加SortedSet
        /// </summary>
        /// <param name="setId"></param>
        /// <param name="item"></param>
        /// <param name="score"></param>
        /// <returns></returns>
        public bool SortedSetAdd(string setId, string item, double score)
        {
            return DoWithRetry(() =>
            {
                using (var cnn = new RedisConnection(sectionName, dbIndex))
                {
                    return cnn.GetDatabase().SortedSetAdd(setId, item, score);
                }
            });
        }

        #endregion

        #region 查询

        /// <summary>
        /// 查询等级段中的SortedSet集合
        /// </summary>
        /// <param name="setId"></param>
        /// <param name="fromRank">起始等级分数</param>
        /// <param name="toRank">结束等级分数</param>
        /// <param name="order"></param>
        /// <returns></returns>
        public List<string> SortedSetGetRangeList(string setId, long fromRank, long toRank, string order = DefaultOrder)
        {
            return DoWithRetry(() =>
            {
                using (var cnn = new RedisConnection(sectionName, dbIndex))
                {
                    var result = new List<string>();
                    var list =
                        cnn.GetDatabase()
                            .SortedSetRangeByRank(setId, fromRank, toRank, order == Order.Descending.ToString().ToLower() ? Order.Descending : Order.Ascending)
                            .ToList();
                    if (list.Any())
                        list.ForEach(x =>
                        {
                            result.Add(x.ToString());
                        });
                    return result;
                }
            });
        }

        /// <summary>
        /// 查询等级段中的SortedSet集合,返回dictionary<value,score>
        /// </summary>
        /// <param name="setId"></param>
        /// <param name="fromRank"></param>
        /// <param name="toRank"></param>
        /// <param name="order"></param>
        /// <returns></returns>
        public Dictionary<string, double> SortedSetGetRangeDic(string setId, long fromRank, long toRank, string order = DefaultOrder)
        {
            return DoWithRetry(() =>
            {
                using (var cnn = new RedisConnection(sectionName, dbIndex))
                {
                    var result = new Dictionary<string, double>();
                    var list =
                        cnn.GetDatabase()
                            .SortedSetRangeByRankWithScores(setId, fromRank, toRank,
                              order == Order.Descending.ToString().ToLower() ? Order.Descending : Order.Ascending)
                            .ToList();
                    if (list.Any())
                        list.ForEach(x =>
                        {
                            result.Add(x.Element, x.Score);
                        });
                    return result;
                }
            });
        }

        /// <summary>
        /// 获取SortedSet集合区间,返回分页信息
        /// </summary>
        /// <param name="setid"></param>
        /// <param name="min"></param>
        /// <param name="max"></param>
        /// <param name="pageIndex"></param>
        /// <param name="pageSize"></param>
        /// <param name="order"></param>
        /// <returns></returns>
        public PagedList<string> SortedSetGetPagedList(string setid, long min, long max, int pageIndex = 1, int pageSize = 20, string order = DefaultOrder)
        {
            return DoWithRetry(() =>
            {
                using (var cnn = new RedisConnection(sectionName, dbIndex))
                {
                    var count = cnn.GetDatabase().SortedSetLength(setid, min, max);
                    if (count > 0)
                    {
                        var list = cnn.GetDatabase()
                            .SortedSetRangeByScoreWithScores(setid, min, max, Exclude.None,
                            order == Order.Descending.ToString().ToLower() ? Order.Descending : Order.Ascending,
                            (pageIndex - 1) * pageSize, pageSize);
                        if ((list != null) && (list.Length > 0))
                        {
                            var result = new List<string>();
                            list.ToList().ForEach(x =>
                            {
                                if ((x != null) && x.Element.HasValue)
                                {
                                    var value = x.Element.ToString();
                                    result.Add(value);
                                }
                            });
                            return new PagedList<string>
                            {
                                PageIndex = pageIndex,
                                PageSize = pageSize,
                                Count = count,
                                List = result
                            };
                        }
                    }
                    return new PagedList<string>();
                }
            });
        }

        /// <summary>
        /// 根据Score范围获取SortedSet集合
        /// </summary>
        /// <param name="setId"></param>
        /// <param name="minScore"></param>
        /// <param name="maxScore"></param>
        /// <returns></returns>
        public List<string> SortedSetGetRangeByScore(string setId, long minScore, long maxScore)
        {
            return DoWithRetry(() =>
            {
                using (var cnn = new RedisConnection(sectionName, dbIndex))
                {
                    var result = new List<string>();
                    var list = cnn.GetDatabase().SortedSetRangeByValue(setId, minScore, maxScore).ToList();
                    if (list.Any())
                        list.ForEach(x =>
                        {
                            if (x.HasValue)
                                result.Add(x.ToString());
                        });
                    return result;
                }
            });
        }


        /// <summary>
        /// 获取SortedSet长度
        /// </summary>
        /// <param name="setId"></param>
        /// <returns></returns>
        public long SortedSetGetLength(string setId)
        {
            return DoWithRetry(() =>
            {
                using (var cnn = new RedisConnection(sectionName, dbIndex))
                {
                    return cnn.GetDatabase().SortedSetLength(setId);
                }
            });
        }

        /// <summary>
        /// 根据值范围儿取SortedSet长度
        /// </summary>
        /// <param name="setId"></param>
        /// <param name="minScore"></param>
        /// <param name="maxScore"></param>
        /// <returns></returns>
        public long SortedSetGetLength(string setId, double minScore, double maxScore)
        {
            return DoWithRetry(() =>
            {
                using (var cnn = new RedisConnection(sectionName, dbIndex))
                {
                    return cnn.GetDatabase().SortedSetLength(setId, minScore, maxScore);
                }
            });
        }


        /// <summary>
        ///获取SortedSet中某个值所在的序号
        /// </summary>
        /// <param name="setId"></param>
        /// <param name="item"></param>
        /// <param name="order"></param>
        /// <returns></returns>
        public long? SortedSetGetScore(string setId, string item, string order = DefaultOrder)
        {
            return DoWithRetry(() =>
            {
                using (var cnn = new RedisConnection(sectionName, dbIndex))
                {
                    return cnn.GetDatabase()
                        .SortedSetRank(setId, item,
                            order == Order.Descending.ToString().ToLower() ? Order.Descending : Order.Ascending);
                }
            });
        }



        /// <summary>
        /// 获取SortedSet中某个值所在的序号
        /// </summary>
        /// <param name="setId"></param>
        /// <param name="item"></param>
        /// <returns></returns>
        public double? SortedSetGetScore(string setId, string item)
        {
            return DoWithRetry(() =>
            {
                using (var cnn = new RedisConnection(sectionName, dbIndex))
                {
                    return cnn.GetDatabase().SortedSetScore(setId, item);
                }
            });
        }

        #endregion

        #region 修改
        /// <summary>
        /// SortedSet计数器+,对应的score在原来的基础上加score
        /// </summary>
        /// <param name="setId"></param>
        /// <param name="item"></param>
        /// <param name="score"></param>
        /// <returns></returns>
        public double SetSortedSetItemIncrement(string setId, string item, double score = 1)
        {
            return DoWithRetry(() =>
            {
                using (var cnn = new RedisConnection(sectionName, dbIndex))
                {
                    return cnn.GetDatabase().SortedSetIncrement(setId, item, score);
                }
            });
        }


        /// <summary>
        ///SortedSet计数器-,对应的score在原来的基础上减score
        /// </summary>
        /// <param name="setId"></param>
        /// <param name="item"></param>
        /// <param name="score"></param>
        /// <returns></returns>
        public double SortedSetItemDecrement(string setId, string item, double score = -1)
        {
            return DoWithRetry(() =>
            {
                using (var cnn = new RedisConnection(sectionName, dbIndex))
                {
                    return cnn.GetDatabase().SortedSetDecrement(setId, item, score);
                }
            });
        }

        ///<summary>
        ///按增量递增存储在键上的数字。如果密钥不存在，
        ///在执行操作之前将其设置为0。如果密钥
        ///包含错误类型的值或包含不可表示的字符串
        ///作为整数。此操作限制为64位有符号整数。
        /// </summary>
        /// <param name="setId"></param>
        /// <param name="item"></param>
        /// <returns></returns>
        public double SetStringIncrement(string setId, long item=1)
        {
            return DoWithRetry(() =>
            {
                using (var cnn = new RedisConnection(sectionName, dbIndex))
                {
                    return cnn.GetDatabase().StringIncrement(setId, item);
                }
            });
        }


        ///<summary>
        ///将存储在键上的数字递减。如果密钥不存在，
        ///在执行操作之前将其设置为0。如果密钥
        ///包含错误类型的值或包含不可表示的字符串
        ///作为整数。此操作限制为64位有符号整数。
        /// </summary>
        /// <param name="setId"></param>
        /// <param name="item"></param>
        /// <returns></returns>
        public double SetStringDecrement(string setId, long item=1)
        {
            return DoWithRetry(() =>
            {
                using (var cnn = new RedisConnection(sectionName, dbIndex))
                {
                    return cnn.GetDatabase().StringDecrement(setId, item);
                }
            });
        }

        #endregion

        #region  删除
        /// <summary>
        ///删除某个值对应的SortedSet
        /// </summary>
        /// <param name="setId"></param>
        /// <param name="item"></param>
        /// <returns></returns>
        public bool SortedSetRemove(string setId, string item)
        {
            return DoWithRetry(() =>
            {
                using (var cnn = new RedisConnection(sectionName, dbIndex))
                {
                    return cnn.GetDatabase().SortedSetRemove(setId, item);
                }
            });
        }

        /// <summary>
        ///移除某个序号范围的SortedSet
        /// </summary>
        /// <param name="setId"></param>
        /// <param name="fromRank"></param>
        /// <param name="toRank"></param>
        /// <returns></returns>
        public long SortedSetRemoveByRank(string setId, long fromRank, long toRank)
        {
            return DoWithRetry(() =>
            {
                using (var cnn = new RedisConnection(sectionName, dbIndex))
                {
                    return cnn.GetDatabase().SortedSetRemoveRangeByRank(setId, fromRank, toRank);
                }
            });
        }

        /// <summary>
        ///移除某个score范围的SortedSet
        /// </summary>
        /// <param name="setId"></param>
        /// <param name="minScore"></param>
        /// <param name="maxScore"></param>
        /// <returns></returns>
        public long SortedSetRemoveByScore(string setId, double minScore, double maxScore)
        {
            return DoWithRetry(() =>
            {
                using (var cnn = new RedisConnection(sectionName, dbIndex))
                {
                    return cnn.GetDatabase().SortedSetRemoveRangeByScore(setId, minScore, maxScore);
                }
            });
        }
        #endregion

        #endregion

        #region Lists操作 先进先出

        /// <summary>
        /// 进队
        /// </summary>
        /// <param name="listId"></param>
        /// <param name="value"></param>
        public long QueueEnqueue(string listId, string value)
        {
            return DoWithRetry(() =>
            {
                using (var cnn = new RedisConnection(sectionName, dbIndex))
                {
                    return cnn.GetDatabase().ListLeftPush(listId, value);
                }
            });
        }

        /// <summary>
        /// 批量进队
        /// </summary>
        /// <param name="listId"></param>
        /// <param name="values"></param>
        public bool QueueEnqueues(string listId, List<string> values)
        {
            return DoWithRetry(() =>
            {
                using (var cnn = new RedisConnection(sectionName, dbIndex))
                {
                    var batch = cnn.GetDatabase().CreateBatch();
                    for (int i = 0; i < values.Count; i++)
                    {
                        batch.ListLeftPushAsync(listId, values[i]);
                    }
                    batch.Execute();
                    return true;
                }
            });
        }

        /// <summary>
        /// 出队
        /// </summary>
        /// <param name="listId"></param>
        /// <returns></returns>
        public string QueueDnqueue(string listId)
        {
            return DoWithRetry(() =>
            {
                string result;
                using (var cnn = new RedisConnection(sectionName, dbIndex))
                {
                    result = cnn.GetDatabase().ListRightPop(listId);

                    if (!string.IsNullOrEmpty(result))
                    {
                        return result;
                    }

                    // 在多写队列中， 比如F5后面挂了多个redis。
                    for (int i = 0; i < cnn.Pool.PoolSize - 1; i++)
                    {
                        result = cnn.GetDatabaseFromNextConnection().ListRightPop(listId);

                        if (!string.IsNullOrEmpty(result))
                        {
                            return result;
                        }
                    }

                    return null;
                }
            });
        }

        /// <summary>
        ///实体进队
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="listId"></param>
        /// <param name="t"></param>
        public long QueueEnqueue<T>(string listId, T t) where T : class, new()
        {
            return DoWithRetry(() =>
            {
                using (var cnn = new RedisConnection(sectionName, dbIndex))
                {
                    var value = t.ToJson();// JsonHelper.NToJson(t);
                    return cnn.GetDatabase().ListLeftPush(listId, value);
                }
            });
        }

        /// <summary>
        /// 批量实体进队
        /// </summary>
        /// <param name="listId"></param>
        /// <param name="values"></param>
        public bool QueueEnqueues<T>(string listId, List<T> values)
        {
            return DoWithRetry(() =>
            {
                using (var cnn = new RedisConnection(sectionName, dbIndex))
                {
                    var batch = cnn.GetDatabase().CreateBatch();

                    for (int i = 0; i < values.Count; i++)
                    {
                        batch.ListLeftPushAsync(listId, values[i].ToJson());//JsonHelper.NToJson(values[i])
                    }
                    batch.Execute();
                    return true;
                }
            });
        }

        /// <summary>
        /// 实体出队
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="listId"></param>
        /// <returns></returns>
        public T QueueDnqueue<T>(string listId) where T : class, new()
        {
            return DoWithRetry(() =>
            {
                using (var cnn = new RedisConnection(sectionName, dbIndex))
                {
                    var json = cnn.GetDatabase().ListRightPop(listId);
                    if (json.IsNullOrEmpty)
                        return default(T);
                    return json.ToString().JsonToObject<T>();//JsonHelper.NToData<T>(json.ToString());
                }
            });
        }

        /// <summary>
        /// 获取队列元素（不需要出队列）
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="listId"></param>
        /// <param name="start"></param>
        /// <param name="stop"></param>
        /// <returns></returns>
        public List<T> QueueGetList<T>(string listId, long start = 0, long stop = -1) where T : class, new()
        {
            return DoWithRetry(() =>
            {
                using (var cnn = new RedisConnection(sectionName, dbIndex))
                {
                    var result = new List<T>();
                    var list = cnn.GetDatabase().ListRange(listId, start, stop).ToList();
                    if (list.Count > 0)
                        list.ForEach(x =>
                        {
                            if (x.HasValue)
                            {
                                var value = x.ToString().JsonToObject<T>(); // JsonHelper.NToData<T>(x);
                                result.Add(value);
                            }
                        });
                    return result;
                }
            });
        }

        /// <summary>
        /// 获取队列元素
        /// </summary>
        /// <typeparam name=""></typeparam>
        /// <param name=""></param>
        /// <param name="listId"></param>
        /// <param name="start"></param>
        /// <param name="stop"></param>
        /// <returns></returns>
        public List<string> QueueGetList(string listId, long start = 0, long stop = -1)
        {
            return DoWithRetry(() =>
            {
                using (var cnn = new RedisConnection(sectionName, dbIndex))
                {
                    var result = new List<string>();

                    var list = cnn.GetDatabase().ListRange(listId, start, stop).ToList();

                    if (list.Any())
                        list.ForEach(x =>
                        {
                            result.Add(x.ToString());
                        });
                    return result;
                }
            });
        }

        /// <summary>
        /// 获取队列长度
        /// </summary>
        /// <param name="listId"></param>
        /// <returns></returns>
        public long QueueCount(string listId)
        {
            return DoWithRetry(() =>
            {
                using (var cnn = new RedisConnection(sectionName, dbIndex))
                {
                    return cnn.GetDatabase().ListLength(listId);
                }
            });
        }

        #endregion

        #region 命令操作
        /// <summary>
        /// 执行命令
        /// </summary>
        /// <param name="command"></param>
        /// <param name="args"></param>
        public void Excute(string command, object[] args)
        {
            DoWithRetry(() =>
            {
                using (var cnn = new RedisConnection(sectionName, dbIndex))
                {
                    return cnn.GetDatabase().Execute(command, args);
                }
            });
        }
        #endregion

        #region 异常日志相关操作
        /// <summary>
        /// 插入异常警告日志到Redis
        /// </summary>
        /// <param name="service_name">服务名称</param>
        /// <param name="hashIdstring"></param>
        /// <param name=""></param>
        /// <param name="exp"></param>
        public bool SaveWarnLog(string  service_name, string messageTitle, Exception exp)
        {
            return DoWithRetry(() =>
            {
                using (var cnn = new RedisConnection(sectionName, dbIndex))
                {
                    string key = Guid.NewGuid().ToString().Replace("-", "").ToUpper();

                    var exceptionLogInfo = new RedisExceptionLogInfo()
                    {
                        id = key,
                        exception_type = 100,
                        service_name = service_name,
                        exception_title = messageTitle,
                        detail = exp.StackTrace,
                        create_date = DateTime.Now,
                        status = 100
                    };

                    return cnn.GetDatabase().HashSet(exceptionHashId, key, exceptionLogInfo.ToJson());
                }
            });
        }

        /// <summary>
        /// 插入异常错误日志到Redis
        /// </summary>
        /// <param name="service_name">服务名称</param>
        /// <param name="messageTitle"></param>
        /// <param name="exp"></param>
        public bool SaveErrorLog(string service_name,string messageTitle, Exception exp)
        {
            return DoWithRetry(() =>
            {
                using (var cnn = new RedisConnection(sectionName, dbIndex))
                {
                    string key = Guid.NewGuid().ToString().Replace("-", "").ToUpper();

                    var exceptionLogInfo = new RedisExceptionLogInfo()
                    {
                        id = key,
                        exception_type = 102,
                        service_name = service_name,
                        exception_title = messageTitle,
                        detail = exp.StackTrace,
                        create_date = DateTime.Now,
                        status = 100
                    };

                    return cnn.GetDatabase().HashSet(exceptionHashId, key, exceptionLogInfo.ToJson());
                }
            });
        }

        /// <summary>
        /// 批量插入异常错误日志
        /// </summary>
        /// <param name="service_name">服务名称</param>
        /// <param name="messageTitles"></param>
        /// <param name="exps"></param>
        public bool SaveErrorLogs(string service_name, List<string> messageTitles, List<Exception> exps)
        {

            return DoWithRetry(() =>
            {
                using (var cnn = new RedisConnection(sectionName, dbIndex))
                {
                    int index = 0;
                    List<string> logInfoKeys = new List<string>();
                    List<RedisExceptionLogInfo> logInfos = new List<RedisExceptionLogInfo>();

                    foreach (var item in messageTitles)
                    {
                        string key = Guid.NewGuid().ToString().Replace("-", "").ToUpper();
                        logInfoKeys.Add(key);
                        logInfos.Add(new RedisExceptionLogInfo()
                        {
                            id = key,
                            exception_type = 102,
                            service_name = service_name,
                            exception_title = item,
                            detail = exps[index].StackTrace,
                            create_date = DateTime.Now,
                            status = 100
                        });
                        index++;
                    }

                    var batch = cnn.GetDatabase().CreateBatch();
                    for (int i = 0; i < logInfos.Count; i++)
                    {
                        batch.HashSetAsync(exceptionHashId, logInfos[i].id, logInfos[i].ToJson());
                    }
                    batch.Execute();
                    return true;
                }
            });
        }
        #endregion

        #region 操作方法重试包装

        private T DoWithRetry<T>(Func<T> func)
        {
            var counter = 0;
            while (counter <= busyRetry)
            {
                try
                {
                    return func();
                }
                catch (Exception ex)
                {

                    counter++;

                    string retryCountMsg = string.Empty;

                    if (ex is TimeoutException)
                    {
                        retryCountMsg = string.Format("TimeoutException Redis<T>操作超时，等待随后重试。当前已经重试：{0};ex:{1}", counter, ex.Message);
                    }
                    else if (ex is RedisConnectionException)
                    {
                        retryCountMsg = string.Format("RedisConnectionException Redis<T>连接异常，等待随后重试。当前已重试：{0};ex:{1}", counter, ex.Message);
                    }
                    else if (ex is RedisServerException && ex.Message.Contains("MOVED"))
                    {
                        retryCountMsg = string.Format("RedisConnectionException Redis<T> MOVED 异常，等待随后重试。当前已重试：{0};ex:{1}", counter, ex.Message);
                    }
                    else
                    {
                        throw ex;
                    }

                    //将重试写成错误，引起重视
                    //LogHelper.WriteRedisLog(retryCountMsg);

                    if (counter > busyRetry)
                        throw ex;  // 大于重试次数，将直接抛出去

                    Thread.Sleep(counter * busyRetryWaitMS);
                }
            }
            return default(T);
        }

        private void DoWithRetry(Action action)
        {
            var counter = 0;
            while (counter <= busyRetry)
            {
                try
                {
                    action();
                    return;
                }
                catch (Exception ex)
                {
                    counter++;

                    string retryCountMsg = string.Empty;

                    if (ex is TimeoutException)
                    {
                        retryCountMsg = string.Format("TimeoutException Redis<T>操作超时，等待随后重试。当前已经重试：{0};ex:{1}", counter, ex.Message);
                    }
                    else if (ex is RedisConnectionException)
                    {
                        retryCountMsg = string.Format("RedisConnectionException Redis<T>连接异常，等待随后重试。当前已重试：{0};ex:{1}", counter, ex.Message);
                    }
                    else
                    {
                        throw ex;
                    }

                    //将重试写成info，引起重视
                    //LogManager.PushLog(retryCountMsg, true);
                    //LogHelper.WriteRedisLog(retryCountMsg);

                    if (counter > busyRetry)
                        throw ex;  // 大于重试次数，将直接抛出去
                    Thread.Sleep(counter * busyRetryWaitMS);
                }
            }
        }
        #endregion

        
    }
}
